#include <am.h>
#include <klib.h>

static Context* (*user_handler)(Event, Context*) = NULL;

Context* __am_irq_handle(Context *c) {
    if (user_handler) {
    Event ev = {0};
    switch (c->mcause) {
      case 11: //eviroment call from machine mode
        switch(c->gpr[17]){
	  case -1 : ev.event = EVENT_YIELD; c->mepc+=4;;break;//yield
	  case 0 : case 1 : case 2 : case 3 : case 4 : case 7 : 
	  case 8 : case 9 : case 19 :
		    ev.event = EVENT_SYSCALL; c->mepc+=4;break;
          default : ev.event = EVENT_ERROR; break;
	}break;
       case 0x8000000000000007:
	         ev.event = EVENT_IRQ_TIMER;break;
      default :  ev.event = EVENT_ERROR; break;//other mode
    }


    c = user_handler(ev, c);
    assert(c != NULL);
  }

  return c;
}

extern void __am_asm_trap(void);

bool cte_init(Context*(*handler)(Event, Context*)) {
  // initialize exception entry
  asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));

  // register event handler
  user_handler = handler;

  return true;
}

Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {
  return NULL;
}

void yield() {
  asm volatile("li a7, -1; ecall");
}

bool ienabled() {
  return false;
}

void set_mie(){
  asm volatile("addi sp, sp, -8");
  asm volatile("sd a0, (sp)");
  asm volatile("li a0, 128");
  asm volatile("csrw mie, a0");
  asm volatile("ld a0, (sp)");
  asm volatile("addi sp, sp, 8");
}

void clear_mie(){
  asm volatile("addi sp, sp, -8");
  asm volatile("sd a0, (sp)");
  asm volatile("li a0, 0");
  asm volatile("csrw mie, a0");
  asm volatile("ld a0, (sp)");
  asm volatile("addi sp, sp, 8");
}

void iset(bool enable) {
  if(enable){
    asm volatile("csrsi mstatus,8");
    set_mie();
  }else{
    asm volatile("csrci mstatus,8");
    clear_mie();
  }
}
